module mculib.arm.semihosting;

import ldc.llvmasm;



version(LDC){}else static assert(0,"Unsupported compiler");



/**
    semihosting 操作选项
    See_Also: 
    SYS = http://www.keil.com/support/man/docs/armcc/armcc_pge1358787045051.htm
*/

final abstract class DSemihosting
{
    static size_t write(T)(in size_t fileHandle,in T[] data)
    {
        uint[3] message = [
            cast(uint)fileHandle,
            cast(uint)data.ptr,
            cast(uint)(data.length * T.sizeof)
        ];
        return cast(size_t)call(SYS.Write,&message);
    }

    static void write(T:ubyte)(in T data)
    {
        call(SYS.WriteC,&data);
    }

    static void write(T)(in T* data)
    {
        call(SYS.Write0,data);
    }
}

// todo: 未完成
struct File
{
    int handle;

    bool open(in string name, in FMODE mode)
    {
        uint[3] message = [
            cast(uint)name.ptr,
            cast(uint)mode,
            cast(uint)name.length
        ];
        return cast(bool)call(SYS.Open,&message);
    }

    bool close()
    {
        uint[1] message = [
            cast(uint)handle,
        ];
        return (call(SYS.Close,&message) == 0);
    }
}

private 
int call(in SYS operation, in void* message)
{
    version(ARM_Thumb){
        return __asm!int("bkpt 0xAB", "={r0}, ~{r0}, ~{r1}", operation, message);
    }else{
        return __asm!int("bkpt 0x123456", "={r0}, ~{r0}, ~{r1}", operation, message);
    }
}


// SVC_Handler
private bool isThumb()
{
    return __asm!bool("bic r2,lr,#0xFFFFFFFE","={r2}");
}


enum SYS : uint
{
    None = 0,
    Open = 0x01,            ///< 在主机上开启一个文件
    Close = 0x02,           ///< 关闭一个文件
    WriteC = 0x03,          ///< 输出一个字符到控制台
    Write0 = 0x04,          ///< 输出一个字符串到控制台
    Write = 0x05,           ///< 输出一个字符串到文件
    Read = 0x06,            ///< 从文件读取数据
    ReadC = 0x07,           ///< 从控制台读取一个字符
    IsError = 0x08,         ///< 检查是否有错误发生
    IsTTY = 0x09,           ///< 检查是否是一个终端设备
    Seek = 0x0A,            ///< 移动文件指针
    FLen = 0x0C,            ///< 获取文件长度
    TmpName = 0x0D,         ///< 获取临时文件名
    Remove = 0x0E,          ///< 删除文件
    Rename = 0x0F,          ///< 重命名文件
    Clock = 0x10,           ///< 获取系统时钟
    Time = 0x11,            ///< 获取系统时间
    System = 0x12,          ///< 运行系统命令
    ErrNo = 0x13,           ///< 获取错误代码
    GetCmdLine = 0x15,      ///< 获取命令行参数
    HeapInfo = 0x16,        ///< 获取堆信息
    EnterSVC = 0x17,        ///< 进入系统调用
    ReportException = 0x18, ///< 报告异常
    Elapsed = 0x30,         ///< 获取已用时间
    TickFreq = 0x31,        ///< 获取时钟频率
}

enum FMODE : uint
{
    Read = 0,               ///< 读取
    ReadBinary = 0x01,      ///< 读取二进制
    ReadWrite = 0x02,       ///< 读取和写入
    ReadWriteBinary = 0x03, ///< 读取、写入和二进制
    Write = 0x04,           ///< 写入
    WriteBinary = 0x05,     ///< 写入二进制
    WriteAppend = 0x06,     ///< 追加写入
    WriteAppendBinary = 0x07, ///< 追加写入二进制
    Append = 0x08,          ///< 追加写入
    AppendBinary = 0x09,    ///< 追加写入二进制
    ReadWriteAppend = 0x0A, ///< 读取、写入和追加写入
    ReadWriteAppendBinary = 0x0B, ///< 读取、写入、追加写入和二进制
}


